package com.glp.work.flow.service.impl;

import com.alibaba.fastjson.JSON;
import com.glp.common.reponse.BaseResult;
import com.glp.fbs.api.dto.user.PersonInfoDto;
import com.glp.work.flow.constant.APICode;
import com.glp.work.flow.constant.Constants;
import com.glp.work.flow.constant.OrderOperation;
import com.glp.work.flow.dto.UserDTO;
import com.glp.work.flow.exception.APIException;
import com.glp.work.flow.mapper.WfBatchMapper;
import com.glp.work.flow.mapper.WfFormSnapshotMapper;
import com.glp.work.flow.mapper.WfOrderMapper;
import com.glp.work.flow.mapper.WfTaskAssignMapper;
import com.glp.work.flow.pojo.*;
import com.glp.work.flow.request.MessageEventReceivedRequest;
import com.glp.work.flow.request.OrderApprovalDTO;
import com.glp.work.flow.request.OrderBatchApprovalDTO;
import com.glp.work.flow.response.WfOrderResultDTO;
import com.glp.work.flow.service.*;
import com.glp.work.flow.utils.DateUtils;
import com.glp.work.flow.utils.RedisManage;
import com.glp.work.flow.workflow.plugin.flowable.service.FlowTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.common.engine.api.FlowableTaskAlreadyClaimedException;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * ]
 * 工单管理服务
 *
 * @author jhuang1
 */
@Service
@Slf4j
public class WfProcessServiceImpl implements WfProcessService {

    @Resource
    private FlowTaskService flowTaskService;
    @Resource
    private UserService userService;
    @Autowired
    private RedisManage redisManage;
    @Resource
    private WfFormService wfFormService;
    @Resource
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private WfOrderMapper wfOrderMapper;

    @Resource
    private WfBatchMapper wfBatchMapper;
    @Resource
    private WfBatchService wfBatchService;
    @Resource
    private WfTaskAssignMapper wfTaskAssignMapper;

    @Autowired
    public UserTaskAssignService userTaskAssignService;

    @Resource
    private WfFormSnapshotMapper wfFormSnapshotMapper;

    @Value("${sms.yzm:1}")
    private String yzm;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String orderApproval(OrderApprovalDTO orderApprovalDTO) {
        log.info("工单审核，开始或取当前用户信息！{}", orderApprovalDTO.getUserNo());
        String exectionId = null;
        BaseResult<UserDTO> b = userService.getPersonInfo(orderApprovalDTO.getUserNo());
        UserDTO user;
        if (b == null || b.getData() == null) {
            throw new APIException(APICode.DATA_ERROR, "工单审核异常！当前用户信息不存在！");
        }
        user = b.getData();
        HistoricTaskInstance hisTaskInst = historyService.createHistoricTaskInstanceQuery().taskId(orderApprovalDTO.getTaskId()).singleResult();
        if (hisTaskInst != null) {
            if (hisTaskInst.getEndTime() != null) {
                BaseResult<UserDTO> hisUserDto = userService.getPersonInfo(hisTaskInst.getAssignee());
                UserDTO hisUser = hisUserDto.getData();
                throw new APIException(APICode.DATA_ERROR, "当前任务已被完成！完成人=" + hisUser.getName());
            }
            String processId = null;
            processId = hisTaskInst.getProcessInstanceId();
            if (Constants.STATUS_1.equals(yzm)) {
                checkYzm(orderApprovalDTO);
            }

            log.info("工单审核，根据任务ID查询流程实例信息！taskId={}，结果：processId={}", orderApprovalDTO.getTaskId(), processId);
            WfOrder record = new WfOrder();
            {//或取平台ID
                record.setProcessId(processId);
                record = wfOrderMapper.selectOne(record);
                if (record == null) {
                    throw new APIException(APICode.DATA_ERROR, "工单审核异常！工单信息不存在！");
                }
            }
            {
                log.info("工单审核，校验当前任务办理人是否正确,{},{},{}", orderApprovalDTO.getUserNo(), orderApprovalDTO.getTaskId(), processId);
                List<Task> list = taskService.createTaskQuery().taskCandidateOrAssigned(orderApprovalDTO.getUserNo()).processInstanceId(processId).list();
                if (CollectionUtils.isNotEmpty(list)) {
                    Task task = list.get(0);
                    if (task == null || !task.getId().equals(orderApprovalDTO.getTaskId())) {
                        throw new APIException(APICode.DATA_ERROR, "工单审核异常！请先领取任务！");
                    }
                } else {
                    throw new APIException(APICode.DATA_ERROR, "工单审核异常！请先领取任务！");
                }

            }

            {
                log.info("更新表单信息！{}", processId);
                if (MapUtils.isNotEmpty(orderApprovalDTO.getFormData())) {
                    wfFormService.updateFormData(processId, orderApprovalDTO.getFormData());
                }
            }
            {
                //保存表单快照信息  当前修改表单快照信息只是基于当前节点，没有版本区分
                log.info("更新表单快照信息！{},{}", processId, orderApprovalDTO.getTaskId());
                if (orderApprovalDTO.getFormData() != null) {
                    WfTaskAssign wfTaskAssign = userTaskAssignService.setlectByTaskDefId(hisTaskInst.getProcessDefinitionId(), hisTaskInst.getTaskDefinitionKey());
                    if (wfTaskAssign != null && wfTaskAssign.getTaskDefForm() != null) {
                        WfFormSnapshot wfFormSnapshot = new WfFormSnapshot();
                        wfFormSnapshot.setProcessId(hisTaskInst.getProcessInstanceId());
                        wfFormSnapshot.setTaskId(hisTaskInst.getId());
                        wfFormSnapshot.setFormCode(wfTaskAssign.getTaskDefForm());
                        wfFormSnapshot.setFormData(JSON.toJSONString(orderApprovalDTO.getFormData()));
                        wfFormSnapshot.setCreateUser(orderApprovalDTO.getUserNo());
                        wfFormSnapshot.setCreateTime(DateUtils.getCurrent());
                        wfFormSnapshotMapper.insertSelective(wfFormSnapshot);
                    }
                }
            }

            {
                log.info("开始处理工单。{}", processId);
                FlowTaskDto flowTaskDto = new FlowTaskDto();
                flowTaskDto.setAppId(record.getAppId());
                flowTaskDto.setProcInsId(processId);
                flowTaskDto.setPass(orderApprovalDTO.getResult());
                flowTaskDto.setComment(orderApprovalDTO.getComment());
                flowTaskDto.setAssignee(user.getUserNo());
                flowTaskDto.setAssigneeName(user.getName());
                flowTaskDto.setFormData(orderApprovalDTO.getProcessVariable());
                flowTaskDto.setTaskId(orderApprovalDTO.getTaskId());
                flowTaskDto.setProcessVariable(orderApprovalDTO.getProcessVariable());
                flowTaskDto.setHandWritingSignatureData(orderApprovalDTO.getHandWritingSignatureData());
                flowTaskDto.setTargetActivityId(orderApprovalDTO.getTargetActivityId());
                flowTaskDto.setDynamicBusinessScope(orderApprovalDTO.getBusinessScopebCode());
                if (CollectionUtils.isNotEmpty(orderApprovalDTO.getUserNos())) {
                    flowTaskDto.setUserNos(orderApprovalDTO.getUserNos());
                }
                flowTaskDto.setProcDefId(hisTaskInst.getProcessDefinitionId());
                exectionId = flowTaskService.userAudit(flowTaskDto);
            }
            return exectionId;
        } else {
            throw new APIException(APICode.DATA_ERROR, "工单不存在！！");
        }
    }

    private void checkYzm(OrderApprovalDTO orderApprovalDTO) {
        Task task = taskService.createTaskQuery().taskId(orderApprovalDTO.getTaskId()).singleResult();
        String processDefinitionId = task.getProcessDefinitionId();
        String taskDefinitionKey = task.getTaskDefinitionKey();
        WfTaskAssign wfTaskAssign = new WfTaskAssign();
        wfTaskAssign.setTaskDefId(taskDefinitionKey);
        wfTaskAssign.setProcDefId(processDefinitionId);
        wfTaskAssign = wfTaskAssignMapper.selectOne(wfTaskAssign);
        log.info("是否配置验证码审批sms：{}", wfTaskAssign.getSms());
        if (Constants.STATUS_1.equals(wfTaskAssign.getSms()) && OrderOperation.PASS.name().equals(orderApprovalDTO.getResult())) {
            if (StringUtils.isNotEmpty(orderApprovalDTO.getYzm())) {
                log.info("提交验证码，yzm：{}", orderApprovalDTO.getYzm());
                PersonInfoDto personInfo = userService.getPersonInfo(orderApprovalDTO.getUserNo(), "");
                if (personInfo == null) {
                    throw new APIException(APICode.DATA_ERROR, "用户信息不存在！");
                } else {
                    String s = redisManage.get(personInfo.getPhone());
                    if (!orderApprovalDTO.getYzm().equals(s)) {
                        throw new APIException(APICode.DATA_ERROR, "验证码错误！");
                    }
                }
            } else {
                throw new APIException(APICode.DATA_ERROR, "请输入验证码！");
            }
        }
    }


    @Override
    public void messageEventReceived(MessageEventReceivedRequest messageEventReceivedRequest) {
        if (StringUtils.isBlank(messageEventReceivedRequest.getMessageEvent())) {
            throw new APIException(APICode.DATA_ERROR, "MessageEvent不能为空！");
        }
        List<ActivityInstance> actIns = runtimeService.createActivityInstanceQuery().processInstanceId(messageEventReceivedRequest.getProcessId()).unfinished().list();
        if (messageEventReceivedRequest.getProcessId().equals(messageEventReceivedRequest.getExecutionId())) {
            log.info("【提交中间消息通知】ProcessId与ExecutionId相同，根据ProcessID查询ExecutionID。ProcessId={}", messageEventReceivedRequest.getProcessId());
            if (CollectionUtils.isEmpty(actIns)) {
                throw new APIException(APICode.DATA_ERROR, "流程实例ID不存在！");
            } else if (actIns.size() > 1) {
                Set<String> excIds = actIns.stream().map(ActivityInstance::getExecutionId).collect(Collectors.toSet());
                if (CollectionUtils.isNotEmpty(excIds) && excIds.size() > 1) {
                    throw new APIException(APICode.DATA_ERROR,
                            "流程实例对应多个ExecutionId，请在接口参数中指定ExecutionID！ProcessId="
                                    + messageEventReceivedRequest.getProcessId() + ", ExecutionIds=" + excIds);
                }
            }
            messageEventReceivedRequest.setExecutionId(actIns.get(0).getExecutionId());
        }
        {
            log.info("【提交中间消息通知】更新表单信息！{}", messageEventReceivedRequest.getProcessId());
            if (MapUtils.isNotEmpty(messageEventReceivedRequest.getDynamicForm())) {
                wfFormService.updateFormData(messageEventReceivedRequest.getProcessId(), messageEventReceivedRequest.getDynamicForm());
            }
        }
        try {
            if (StringUtils.isNotBlank(messageEventReceivedRequest.getComment())) {
                runtimeService.setVariableLocal(messageEventReceivedRequest.getExecutionId(), actIns.get(0).getId(), messageEventReceivedRequest.getComment());
            }
            if (messageEventReceivedRequest.getProcessVariable() != null
                    && !messageEventReceivedRequest.getProcessVariable().isEmpty()) {
                runtimeService.messageEventReceived(
                        messageEventReceivedRequest.getMessageEvent(), messageEventReceivedRequest.getExecutionId(), messageEventReceivedRequest.getProcessVariable());
            } else {
                runtimeService.messageEventReceived(
                        messageEventReceivedRequest.getMessageEvent(), messageEventReceivedRequest.getExecutionId());
            }
        } catch (Exception e) {
            log.error("中间消息节点通知失败", e);
            throw new APIException(APICode.DATA_ERROR, "中间消息节点通知失败");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> orderBatchApproval(OrderBatchApprovalDTO orderBatchApprovalDTO) {
        String batchNo = wfBatchService.addWfBatch(orderBatchApprovalDTO);
        List<String> executionIds = new ArrayList<>();
        List<WfOrderResultDTO> wfOrderResultDTOS = orderBatchApprovalDTO.getWfOrderResultDTOS();

        wfOrderResultDTOS.forEach(wfOrderResultDTO -> {
            //判断是否可以批量审批
            Task task = taskService.createTaskQuery().taskId(wfOrderResultDTO.getTaskId()).singleResult();
            Example example = new Example(WfTaskAssign.class);
            example.createCriteria()
                    .andEqualTo("taskDefId", task.getTaskDefinitionKey())
                    .andEqualTo("procDefId", task.getProcessDefinitionId());
            WfTaskAssign wfTaskAssign = wfTaskAssignMapper.selectOneByExample(example);

            if (wfTaskAssign.getTaskDefBatch() == null || !Constants.STATUS_1.equals(wfTaskAssign.getTaskDefBatch())) {
                throw new APIException(APICode.DATA_ERROR, "当前节点不能批量审批，请进行配置！" + task.getName());
            }
            OrderApprovalDTO dto = new OrderApprovalDTO();
            dto.setUserNo(orderBatchApprovalDTO.getUserNo());
            dto.setResult(orderBatchApprovalDTO.getResult());
            dto.setComment(orderBatchApprovalDTO.getComment());
            dto.setFormData(orderBatchApprovalDTO.getFormData());
            dto.setYzm(orderBatchApprovalDTO.getYzm());
            dto.setProcessVariable(orderBatchApprovalDTO.getProcessVariable());
            dto.setTaskId(wfOrderResultDTO.getTaskId());
            try {
                log.info("领取任务：{}", wfOrderResultDTO);
                taskService.claim(wfOrderResultDTO.getTaskId(), orderBatchApprovalDTO.getUserNo());
            } catch (FlowableObjectNotFoundException e) {
                log.error("当前任务不存在！{}", wfOrderResultDTO);
                throw new APIException(APICode.DATA_ERROR, "当前任务不存在！taskId：" + wfOrderResultDTO.getTaskId());
            } catch (FlowableTaskAlreadyClaimedException e) {
                log.error("当前任务已被领取！：{}", wfOrderResultDTO);
                throw new APIException(APICode.DATA_ERROR, "当前任务已被领取！taskId：" + wfOrderResultDTO.getTaskId());
            }
            String s = orderApproval(dto);
            executionIds.add(s);
        });
        WfBatch wfBatch = new WfBatch();
        wfBatch.setBatchNo(batchNo);
        wfBatch.setOrderStatus(orderBatchApprovalDTO.getResult());
        wfBatch.setEndTime(new Date());
        Example example = new Example(WfBatch.class);
        example.createCriteria().andEqualTo("batchNo", batchNo);
        wfBatchMapper.updateByExampleSelective(wfBatch, example);
        return executionIds;
    }

}
